#!/usr/bin/sbcl --noinform

;; TODO
;; Perhaps use proplists instead of packet-*, block-* access routines
(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :lexer)
  (require :yacc)
  (require :cl-utilities))

(defpackage #:libsl
  (:use #:common-lisp #:lexer #:yacc #:cl-utilities)
  (:export #:test))

(in-package #:libsl)

(load "parser")
(load "c-backend")
(load "c#-backend")

;; === UTILITIES ==

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part 
  is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
          for old-pos = 0 then (+ pos part-length)
          for pos = (search part string
                            :start2 old-pos
                            :test test)
          do (write-string string out
                           :start old-pos
                           :end (or pos (length string)))
          when pos do (write-string replacement out)
          while pos))) 

(defun dump(parse-tree)
  (dolist (packet parse-tree)
    (format t "Packet ~A~%~A~%~%" (car packet) packet))
  (format t "~%====~%"))

(defun print-lexer-stream (s)
    (format t "~A~%" (loop repeat 50 collect (multiple-value-list (funcall s)))))

(defun read-file (filename)
  "read all of the file into a string (very fast method)"
  (with-open-file (f filename)
                  (let ((seq (make-string (file-length f))))
                       (read-sequence seq f)
                       seq)))

(defun remove-whitespace (list)
  (mapcar #'(lambda (x) (string-trim '(#\linefeed #\space #\return) x)) list)) ;; #\return == MS linefeed

(defun remove-unused-packets (parse-tree)
  "Return a new parse tree with all unused packets removed"
  (let ((unused-packets (remove-whitespace (split-sequence #\newline (read-file "unusedpackets.txt")))))
       (remove-if #'(lambda (packet) (find  (packet-name packet) unused-packets :test #'string=)) parse-tree)))

(defun only-used-packets (parse-tree)
  "Return a new parse tree with all unused packets removed"
  (let ((unused-packets (remove-whitespace (split-sequence #\newline (read-file "unusedpackets.txt"))))
        (used-packets (remove-whitespace (split-sequence #\newline (read-file "usedpackets.txt")))))
       (remove-if-not #'(lambda (packet) (find  (packet-name packet) used-packets :test #'string=))
                      (remove-if #'(lambda (packet) (find  (packet-name packet) unused-packets :test #'string=)) parse-tree))))

;; === testing ==

(defun test ()
  ;; TODO: remove hardcoded file names
  (let* ((s (lexer (read-file "message_template.msg")))
         (parse-tree (remove-unused-packets (parse *libsl-parser* s))))
         ;;(parse-tree (only-used-packets (parse *libsl-parser* s))))
    ;;(print-lexer-stream s)
    ;;(dump parse-tree)
    (make-c-code parse-tree)
    (make-c#-code parse-tree "OpenSim.Region.ClientStack.FunSLUDP")))
;;  (sb-ext:run-program "/usr/bin/make" () :output t)))

(libsl:test)
